package com.xbongbong.saas.factory.publicrule;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.xbongbong.paas.constant.PaasConstant;
import com.xbongbong.paas.toolbox.exception.XbbException;
import com.xbongbong.paas.toolbox.util.CollectionsUtil;
import com.xbongbong.paas.toolbox.util.DateTimeUtil;
import com.xbongbong.paas.toolbox.util.StringUtil;
import com.xbongbong.saas.domain.entity.ClueRuleEntity;
import com.xbongbong.saas.domain.entity.ClueUserEntity;
import com.xbongbong.saas.domain.entity.RuleClueEntity;
import com.xbongbong.saas.enums.ClueRuleChildEnum;
import com.xbongbong.sys.domain.entity.UserEntity;
import org.springframework.stereotype.Component;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Objects;

/**
 * @author long
 * @version v1.0
 * @date 2020/12/2 14:56
 * @since v1.0
 */
@Component
public class CheckClueRuleNoCommunicate extends AbstractCheckClueRule implements ICheckClueRule{

    @Override
    public List<RuleClueEntity> getBackClueList(UserEntity userEntity, ClueRuleEntity rule, List<RuleClueEntity> clueList, Integer advanceTime) throws XbbException {
        if(advanceTime == null){
            advanceTime = 0;
        }

        List<RuleClueEntity> retList = new ArrayList<>();
        if(rule == null || Objects.equals(rule.getStatus(), 0)){
            return retList;
        }

        IOperateClueRuleValue operateRuleValue = OperateClueRuleValueFactory.operateRuleValueFactory(rule.getRuleType());
        Object ruleValueObject = operateRuleValue.toObject(rule);
        JSONObject ruleValueJson = (JSONObject)ruleValueObject;

        List<String> typeNotIn = JSON.parseArray(ruleValueJson.getJSONArray("clueStatus").toJSONString(), String.class);
        removeRuleNoBack(clueList, typeNotIn);

        List<Long> labelNotIn = JSON.parseArray(ruleValueJson.getJSONArray("label").toJSONString(), Long.class);
        removeRuleLabelNoBack(clueList, labelNotIn);


        Integer type = ruleValueJson.getInteger("type");
        if (Objects.equals(type, ClueRuleChildEnum.LABEL.getCode())) {
            //获取当前用户的最小配置
            /**
             * key:标签的id
             * value：天数
             */
            Map<Long, Integer> mainDayMap = getMinDayMap(ruleValueJson.getJSONArray("restrict"), userEntity);

            Integer day = null;

            Map<Long, ClueUserEntity> clueUserMap = getClueUserMap(userEntity.getCorpid(), userEntity.getUserId(), clueList);

            for (RuleClueEntity clue : clueList) {
                String labelStr = clue.getLabels();
                List<Long> labels = JSONArray.parseArray(labelStr, Long.class);

                day = minDay(labels, mainDayMap);
                //没有在规则限制中
                if (day == null) {
                    continue;
                }
                //提醒的时候，拼接提醒信息
                //原天数
                Integer orDay = day;
                day -= advanceTime;
                day = day < 0 ? 0 : day;


                //线索被分配至今是否没有超过规则时间
                ClueUserEntity clueUser = clueUserMap.get(clue.getId());
                if (!distributionTimeExceedRuleTime(clueUser, day)) {
                    continue;
                }
                /**
                 * 现在时间 - 线索最后联系时间 > 配置
                 * 线索最后联系时间< 现在时间 - 配置
                 */
                Long now = DateTimeUtil.getInt();
                Long minLastConnectTime = now - day * 86400L;
                Long lastConnectTime = clue.getLastConnectTime();

                lastConnectTime = lastConnectTime == null ? 0 : lastConnectTime;

                if (lastConnectTime < minLastConnectTime) {
                    if (advanceTime > 0) {
                        Long time = clueUser.getDistributionTime() > lastConnectTime
                                ? clueUser.getDistributionTime() : lastConnectTime;

                        setLeftDay(clue, userEntity.getName(), rule.getRuleType(), time, orDay);
                    }
                    retList.add(clue);
                }

            }
        } else {
            //获取当前用户的最小配置
            /**
             * key:value
             * {"1":2,"2":6,"3":5}
             */
            JSONObject minObject = getMinObject(ruleValueJson.getJSONArray("restrict"), userEntity, type);

            Integer day = null;

            Map<Long, ClueUserEntity> clueUserMap = getClueUserMap(userEntity.getCorpid(), userEntity.getUserId(), clueList);

            for (RuleClueEntity clue : clueList) {
                if (Objects.equals(type, 0)) {
                    //所有线索统一配置
                    day = (Integer) minObject.get("0");
                } else if (Objects.equals(type, 1)) {
                    //根据线索状态配置
                    Integer clueType = clue.getType();
                    day = (Integer) minObject.get(clueType + "");
                }
                //没有在规则限制中
                if (day == null) {
                    continue;
                }
                //提醒的时候，拼接提醒信息
                //原天数
                Integer orDay = day;
                day -= advanceTime;
                day = day < 0 ? 0 : day;


                //线索被分配至今是否没有超过规则时间
                ClueUserEntity clueUser = clueUserMap.get(clue.getId());
                if (!distributionTimeExceedRuleTime(clueUser, day)) {
                    continue;
                }
                /**
                 * 现在时间 - 线索最后联系时间 > 配置
                 * 线索最后联系时间< 现在时间 - 配置
                 */
                Long now = DateTimeUtil.getInt();
                Long minLastConnectTime = now - day * 86400L;
                Long lastConnectTime = clue.getLastConnectTime();

                lastConnectTime = lastConnectTime == null ? 0 : lastConnectTime;

                if (lastConnectTime < minLastConnectTime) {
                    if (advanceTime > 0) {
                        Long time = clueUser.getDistributionTime() > lastConnectTime
                                ? clueUser.getDistributionTime() : lastConnectTime;

                        setLeftDay(clue, userEntity.getName(), rule.getRuleType(), time, orDay);
                    }
                    retList.add(clue);
                }

            }
        }
        return retList;
    }

    private Integer minDay(List<Long> labels, Map<Long, Integer> minDayMap) {
        Integer day = null;
        if (CollectionsUtil.isEmpty(labels)) {
            return day;
        }
        for (Long label : labels) {
            Integer integer = minDayMap.get(label);
            if (Objects.nonNull(integer)) {
                if (Objects.isNull(day) || (Objects.nonNull(day) && integer < day)) {
                    day = integer;
                }
            }
        }
        return day;
    }

    private Map<Long, Integer> getMinDayMap(JSONArray restrict, UserEntity userEntity) {
        Map<Long, Integer> specialMinDayMap = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
        Map<Long, Integer> allMinDayMap = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
        List<Long> deptIds;
        try {
            deptIds = JSONArray.parseArray(userEntity.getDepartment(), Long.class);
        } catch (Exception e) {
            deptIds = new ArrayList<>();
        }
        if (deptIds == null) {
            deptIds = new ArrayList<>();
        }
        List<Integer> roleIds = new ArrayList<>();
        String role = userEntity.getRoleIds();
        if (StringUtil.isNotEmpty(role)) {
            roleIds = StringUtil.roleIdToListInt(role);
        }
        if (roleIds == null) {
            roleIds = new ArrayList<>();
        }
        for(Object restrictObject : restrict){
            JSONObject restrictJson = (JSONObject)restrictObject;
            JSONArray users = restrictJson.getJSONArray("users");
            JSONArray depts = restrictJson.getJSONArray("depts");
            JSONArray roles = restrictJson.getJSONArray("roles");
            List<String> userIdList = new ArrayList<>();
            List<Long> deptIdList = new ArrayList<>();
            List<Integer> roleIdList = new ArrayList<>();
            if (Objects.nonNull(users)) {
                userIdList = JSON.parseArray(users.toJSONString(), String.class);
            }
            if (Objects.nonNull(depts)) {
                deptIdList = JSON.parseArray(depts.toJSONString(), Long.class);
            }
            if (Objects.nonNull(roles)) {
                roleIdList = JSON.parseArray(roles.toJSONString(), Integer.class);
            }
            deptIdList.retainAll(deptIds);
            roleIdList.retainAll(roleIds);
            Boolean scecialConfig = users != null || depts != null || roles != null;
            Boolean configFail = !userIdList.contains(userEntity.getUserId()) && deptIdList.isEmpty() && roleIdList.isEmpty();
            if(scecialConfig && configFail){
                //对于当前用户无效的配置
                continue ;
            }

            JSONArray array = restrictJson.getJSONArray("array");

            stringKey(array, users, depts, roles, specialMinDayMap, allMinDayMap);
        }
        Iterator<Map.Entry<Long, Integer>> it = allMinDayMap.entrySet().iterator();
        while (it.hasNext()) {
            Map.Entry<Long, Integer> entry = it.next();
            Long key = entry.getKey();

            Integer integer = specialMinDayMap.get(key);
            if (Objects.nonNull(integer)) {
                // 如果某个标签出现在全部和特殊里面，那么去掉全部的标签配置；
                it.remove();
            }
        }
        specialMinDayMap.putAll(allMinDayMap);
        return specialMinDayMap;
    }

    private void stringKey(JSONArray array, JSONArray users, JSONArray depts, JSONArray roles, Map<Long, Integer> specialMinDayMap, Map<Long, Integer> allMinDayMap) {
        for(Object object : array){
            JSONObject jsonObject = (JSONObject)object;
            String key = jsonObject.getString("key");

            List<Long> labels = JSON.parseArray(key, Long.class);

            Integer value = jsonObject.getInteger("value");

            if(users == null && depts == null && roles == null){
                for (Long label : labels) {
                    Integer integer = allMinDayMap.get(label);
                    if (Objects.isNull(integer)) {
                        allMinDayMap.put(label, value);
                        continue;
                    }
                    if (integer < value) {
                        allMinDayMap.put(label, integer);
                    }
                }
                continue ;
            }

            for (Long label : labels) {
                Integer integer = specialMinDayMap.get(label);
                if (Objects.isNull(integer)) {
                    specialMinDayMap.put(label, value);
                    continue;
                }
                if (integer < value) {
                    specialMinDayMap.put(label, integer);
                }
            }
        }
    }


    @Override
    public boolean canGainClue(ClueRuleEntity rule, String corpid,
                               UserEntity userEntity, Long clueId, int dataIdSize, JSONObject data) throws XbbException {
        //此规则不会限制员工获取线索，故返回true;
        return true;
    }


    @Override
    public List<RuleClueEntity> getBackClueList(UserEntity userEntity,
                                                        ClueRuleEntity rule, List<RuleClueEntity> clueList)
            throws XbbException {
        return getBackClueList(userEntity, rule, clueList, null);
    }
}
